﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.InteropServices;
using OpenESSOConfigurator.PresentationLayer.PresentationModels;
using OpenESSOConfigurator.PresentationLayer.EventBroker;
using OpenESSOConfigurator.PresentationLayer.EventBroker.Handlers;
using OpenESSOConfigurator.BusinessLayer.Atoms;

namespace OpenESSOConfigurator.PresentationLayer.UserControls
{
    public partial class WinFormView : UserControl,IView
    {
        private bool dragging;
        private Cursor curPointer;
        private IntPtr hWndCurrent;
        private int clickedCellRowIndex;

        #region external Win32 API import
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            #region Helper methods

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public static implicit operator System.Drawing.Point(POINT p)
            {
                return new System.Drawing.Point(p.X, p.Y);
            }

            public static implicit operator POINT(System.Drawing.Point p)
            {
                return new POINT(p.X, p.Y);
            }

            #endregion
        }
        const int DSTINVERT = 0x00550009;
        [DllImport("gdi32.dll")]
        static extern bool PatBlt(IntPtr hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, uint dwRop);

        [DllImport("user32.dll")]
        static extern IntPtr WindowFromPoint(POINT Point);

        [DllImport("user32.dll")]
        static extern int GetWindowText(int hWnd, StringBuilder text, int count);

        [DllImport("user32.dll")]
        static extern IntPtr GetWindowDC(IntPtr hWnd);

        [DllImport("user32.dll")]
        static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        [DllImport("user32.dll")]
        static extern bool OffsetRect(ref RECT lprc, int dx, int dy);

        [DllImport("user32.dll")]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        [DllImport("user32.dll")]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        [DllImport("user32.dll")]
        public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("user32.dll")]
        public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, int dwFlags);

        [DllImport("user32.dll")]
        public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll")]
        public static extern int GetParent(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern int GetAncestor(IntPtr hWnd, int flags);
        #region Private Win32 Fonction
        private void DrawRevFrame(IntPtr hWnd)
        {
            if (hWnd == IntPtr.Zero)
                return;

            IntPtr hdc = GetWindowDC(hWnd);
            RECT rect;
            GetWindowRect(hWnd, out rect);
            OffsetRect(ref rect, -rect.Left, -rect.Top);

            const int frameWidth = 3;

            PatBlt(hdc, rect.Left, rect.Top, rect.Right - rect.Left, frameWidth, DSTINVERT);
            PatBlt(hdc, rect.Left, rect.Bottom - frameWidth, frameWidth,
                -(rect.Bottom - rect.Top - 2 * frameWidth), DSTINVERT);
            PatBlt(hdc, rect.Right - frameWidth, rect.Top + frameWidth, frameWidth,
                rect.Bottom - rect.Top - 2 * frameWidth, DSTINVERT);
            PatBlt(hdc, rect.Right, rect.Bottom - frameWidth, -(rect.Right - rect.Left),
                frameWidth, DSTINVERT);
        }

        private string GetWindowText(IntPtr hWnd)
        {
            StringBuilder text = new StringBuilder(256);
            if (GetWindowText(hWnd.ToInt32(), text, text.Capacity) > 0)
            {
                return text.ToString();
            }

            return String.Empty;
        }

        private string GetClassName(IntPtr hWnd)
        {
            StringBuilder className = new StringBuilder(100);
            if (GetClassName(hWnd, className, className.Capacity) > 0)
            {
                return className.ToString();
            }
            return String.Empty;
        }

        private string GetApplication(IntPtr hWnd)
        {
            int procId;
            GetWindowThreadProcessId(hWnd, out procId);
            Process proc = Process.GetProcessById(procId);
            return proc.MainModule.ModuleName;
        }

        private string GetParentHandle(IntPtr hWnd)
        {
            if (GetAncestor(hWnd, 2) > 0)
            {
                return GetAncestor(hWnd, 2).ToString();
            }
            return String.Empty;
        }

        private string GetParentWindowText(IntPtr hWnd)
        {
            if (GetAncestor(hWnd, 2) > 0)
            {
                return GetWindowText((IntPtr)GetAncestor(hWnd, 2));
            }
            return String.Empty;
        }
        #endregion

        #endregion 

        public WinFormView()
        {
            curPointer = new Cursor(Assembly.GetExecutingAssembly().GetManifestResourceStream("OpenESSOConfigurator.ResourcesLayer.Cursors.Pointer.cur"));
            InitializeComponent();
            this.winFormBindingSource.DataSource = WinFormPresentationModel.Instance.WinForm;
        }

        private void WinFormView_Load(object sender, EventArgs e)
        {
            WinFormPresentationModel.Instance.RegisterView(this);
            this.Update();
        }

        #region PicturBox1 event Handler
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                dragging = true;
                this.Cursor = curPointer;
                pictureBox1.Image = this.dragBoxImageList.Images[0];
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (dragging)
            {
                dragging = false;
                this.Cursor = Cursors.Default;
                pictureBox1.Image = this.dragBoxImageList.Images[1];
                if (hWndCurrent != IntPtr.Zero)
                {
                    DrawRevFrame(hWndCurrent);
                    //add new title to windowtitledatabinding source
                    WindowTitle wintitle = new WindowTitle();
                    wintitle.Value = GetParentWindowText(hWndCurrent);
                    wintitle.MatchType = "exact";
                    this.windowTitlesBindingSource.Add(wintitle);
                    //
                    hWndCurrent = IntPtr.Zero;
                }
            }
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (dragging)
            {
                IntPtr hWnd = WindowFromPoint(MousePosition);
                if (hWnd == this.pictureBox1.Handle)
                {
                    hWnd = IntPtr.Zero;
                }

                if (hWnd != hWndCurrent)
                {
                    if (hWndCurrent != null)
                    {
                        DrawRevFrame(hWndCurrent);
                    }
                    DrawRevFrame(hWnd);
                    hWndCurrent = hWnd;
                }

                if (hWnd != IntPtr.Zero)
                {
                    this.textBox4.Text = hWnd.ToString();
                    this.textBox5.Text = GetClassName(hWnd);
                    this.textBox6.Text = GetParentHandle(hWnd);
                    this.textBox7.Text = GetParentWindowText(hWnd);
                    this.textBox12.Text = GetApplication(hWnd);
                }
                else
                {
                    this.textBox4.Text = String.Empty;
                    this.textBox5.Text = String.Empty;
                    this.textBox6.Text = String.Empty;
                    this.textBox7.Text = String.Empty;
                    this.textBox12.Text = String.Empty;
                }
            }

        }
        #endregion

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            if (this.radioButton1.Checked == true)
            {
                this.groupBox4.Enabled = true;
                this.radioButton2.Checked = false;
            }
            else
                this.groupBox4.Enabled = false;
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            if (this.radioButton2.Checked == true)
            {
                this.groupBox3.Enabled = true;
                this.radioButton1.Checked = false;
            }
            else
                this.groupBox3.Enabled = false;

        }

        private void dataGridView3_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (this.dataGridView3.Columns[e.ColumnIndex] is DataGridViewImageColumn)
            {
                e.Value = this.dataGridImageList.Images[0];
            }
        }

        #region DataGridView Mouse Event Handler
        private void DataGridView3_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.dataGridView3.CurrentCell is DataGridViewImageCell)
            {
                if (e.Button == MouseButtons.Left)
                {
                    dragging = true;
                    this.Cursor = curPointer;
                    //DataGridViewImageColumn imagecolumn = new DataGridViewImageColumn();
                    //imagecolumn.Image = this.dataGridImageList.Images[1];
                    //this.dataGridView3[e.ColumnIndex, e.RowIndex].Value = imagecolumn;
                    clickedCellRowIndex = this.dataGridView3.SelectedCells[0].RowIndex;
                }

            }

        }

        private void DataGridView3_MouseMove(object sender, MouseEventArgs e)
        {
            if (dragging)
            {
                IntPtr hWnd = WindowFromPoint(MousePosition);
                if (hWnd == this.dataGridView3.Handle)
                {
                    hWnd = IntPtr.Zero;
                }
                if (hWnd != hWndCurrent)
                {
                    if (hWndCurrent != null)
                    {
                        DrawRevFrame(hWndCurrent);
                    }
                    DrawRevFrame(hWnd);
                    hWndCurrent = hWnd;
                }
                if (hWnd != IntPtr.Zero)
                {
                    this.dataGridView3[2, clickedCellRowIndex].Value = hWnd.ToString();
                    this.dataGridView3[3, clickedCellRowIndex].Value = GetClassName(hWnd);
                }
                else
                {
                    this.dataGridView3[2, clickedCellRowIndex].Value = String.Empty;
                    this.dataGridView3[3, clickedCellRowIndex].Value = String.Empty;
                }

            }

        }

        private void DataGridView3_MouseUp(object sender, MouseEventArgs e)
        {
            if (dragging)
            {
                dragging = false;
                this.Cursor = Cursors.Default;
                //DataGridViewImageColumn imagecolumn = new DataGridViewImageColumn();
                //imagecolumn.Image = this.dataGridImageList.Images[0];
                //this.dataGridView3[e.ColumnIndex, e.RowIndex].Value = imagecolumn;
                if (hWndCurrent != IntPtr.Zero)
                {
                    DrawRevFrame(hWndCurrent);
                    hWndCurrent = IntPtr.Zero;
                }
            }

        }
        #endregion 
    }
}
